/**
 * name：grouptable【layui分组表格控件】
 * author：白西龙
 * description：
 *   layui分组表格控件，用于实现页面数据分组，并以树形结构显示。
 *   
 *   1、支持多级分组；
 *   2、支持自定义分组标题；
 *   3、支持分组数据行数显示；
 *   4、所有行数据会增加属性：
 *      $treetype as [d|g] : 数据类型（d:数据;g:分组）
 *      $treeid : 数据分组ID（分组：父ID+id；数据：父ID+行号[不连续]）
 *      $treepid : 父级分组ID（一级分组父ID为$ROOT）
 *      $index4all : 数据行号（从1开始，分组行不计数）
 *      $index4group : 组内数据行号（从1开始，分组行不计数）
 *      $treedepth : 属性结构层级（一级分组层级为0）
 *      $treevalue : 分组值
 *      $treegroupname : 分组名称
 *      $treetext : 分组显示值
 *      $treetitle : 分组标题
 *      $treedatanums : 分组数据行数
 *   5、支持展开全部expandAll/收拢全部foldAll
 * notice：
 *   1、不支持多级表头【未解决】；
 *   2、不支持懒加载【未解决】；
 *   3、不支持分页【未解决】；
 *   4、fixed-left显示问题：如果fixed列宽不够，则数据表中的分组描述语言会显示出来【已优化】；
 *   5、fixed表格不支持鼠标滚轮【已优化】；
 *   6、分组信息合并整行时，fixed-right不会合并【已优化】；
 *   7、分组信息合并整行时速度有点慢【已优化，200行分组耗时约0.3s】；
 *   8、如果有numbers序号列，则第一列必须是序号列，其他列也可再增加【已优化，任意列都可以是序号】；
 *   9、不支持单元格换行显示【已优化，开启后会影响表格渲染速度，460行耗时约0.65s，274行耗时约0.23s，31行耗时约18ms】；
 *   10、不支持统计行【未解决】；
 *   11、fixed-left显示问题：拉宽fixed-left列后，分组标题无法自动计算宽度【已优化】；
 *   12、表格第一列用于分组显示，不支持templet【已优化】；
 *   13、表格第一列用于分组显示，不支持隐藏【已优化，强制修改列顺序，将隐藏列修改到fixedRight之前】；
 * usage：
 *   1、引入js文件
 *   2、引入grouptable layui.use([grouptable])
 *   3、组织参数调用表格render方法 layui.grouptable.render(config typeof Object)
 *     config.defaultClose = true | false(default) : 默认收起所有分组
 *     config.groupLinkage = true | false(default) : 展开时是否同时展开下级
 *     config.dataIndent = true(default) | false : 数据行是否启用缩进（序号列numbers不支持缩进）
 *     config.lineWrap = true | false(default) : 是否开启单元格自动换行（开启后会影响表格渲染速度）
 *     config.groupCols = [groupInfo typeof Object ...] typeof Array : 分组信息定义
 *         groupInfo.field typeof String : 分组列名
 *         groupInfo.name typeof String : 分组描述
 *         groupInfo.tpl typeof String : 分组标题模板（支持html，内置三个转换项）
 *             #name# : 分组描述替换关键字
 *             #value# : 分组值替换关键字（如果定义valueFormat，则替换为转换结果）
 *             #count# : 分组数据行数
 *         groupInfo.valueFormat typeof Function : 分组值转换方法（function(v){return f(v) typeof String}）
 *             v typeof String | Any : 分组值
 *             f(v) typeof String : 分组值转换后结果
 * example：
 *   projectGrid = grouptable.render({
 *      ...
 *      defaultClose: true,//默认收拢
 *      groupLinkage: false,//展开时不自动展开下级
 *      groupCols: [//分组配置
 *              {field:"projUseDept",name:"项目甲方",tpl:"[#name#] = #value# (<span style='color:red;'>#count#</span>)"},
 *              {field:"projType",name:"项目状态",tpl:"[#name#] = #value# (<span style='color:red;'>#count#</span>)",valueFormat:function(v){
 *                  var map = {"601678460235d2e84aa45656690a4f1c":"正常","41E0DDB12A544C5D936B26CF5154619E":"审批中"};
 *                  return map.hasOwnProperty(v)?map[v]:v;
 *              }}
 *      ],
 *      ...
 *   })
 *
 **/

var styleEl = document.createElement('style');
styleEl.innerHTML += '.groupTable-empty {width: 15px;display: inline-block;}';
styleEl.innerHTML += '.groupTable-icon {cursor: pointer;}';
styleEl.innerHTML += '.groupTable-icon .layui-icon-triangle-d:before {content: "\\e623";background-color: transparent;padding: 0px 5px 0px 0px;}';
styleEl.innerHTML += '.groupTable-icon.open .layui-icon-triangle-d:before {content: "\\e625";background-color: transparent;padding: 0px 5px 0px 0px;}';
styleEl.innerHTML += '.layui-table-fixed-l.layui-table-fixed-scroll .layui-table-body::-webkit-scrollbar {display:none !important;}';
styleEl.innerHTML += '.layui-table-fixed-r.layui-table-fixed-scroll:hover {right:0 !important;}';
styleEl.innerHTML += '.layui-table-fixed .layui-table-body:hover {overflow-y: scroll;}';

//styleEl.innerHTML += '.layui-table-cell {padding:0 15px;}';
document.head.appendChild(styleEl);

layui.define(['layer', 'table'], function (exports) {
    var $ = layui.jquery;
    var layer = layui.layer;
    var table = layui.table;
    //console.log = function(){return false};
    var grouptable = {
        // 渲染树形表格
        render: function (param) {
            if(typeof(param.elem) !== 'string' || param.elem.indexOf("#")!=0){
                alert("elem属性不合法！");
                return null;
            }
            var tableOptions = {defaultClose:false, groupLinkage:false, dataIndent:true, lineWrap:false};
            $.extend(true,tableOptions,param,{treeSpid:"$ROOT",treeIdName:"$treeid",treePidName:"$treepid",groupColIndex:0,lazyLoad:false,page:false});
            tableOptions.$initConfig = param;
            window.istime = new Date();
            console.log("============================\r\nrender start:"+(new Date()-window.istime));
            if(tableOptions.lineWrap){
                var styleId = param.elem.substr(1)+"_style";
                if(document.getElementById(styleId)) document.getElementById(styleId).remove();
                var style4table = document.createElement('style');
                style4table.id = styleId;
                style4table.innerHTML = 'div[lay-id="'+param.elem.substr(1)+'"] .layui-table-body .layui-table-cell {height:auto; overflow:visible; text-overflow:inherit; white-space:normal; word-break: break-all;}';
                document.head.appendChild(style4table);
            }
            var tableObject;
            // 获取数据
            if (tableOptions.url) {
                console.log("get data start:"+(new Date()-window.istime));
                var method = tableOptions.method||'get';
                var data = (method.toLowerCase() == "post")? JSON.stringify(tableOptions.where):tableOptions.where;
                $.ajax({
                    url: tableOptions.url, type: method, data:data, async:false, cache: false,
                    contentType: 'application/json; charset=utf-8',
                    success: function (text) {tableObject = grouptable.init(tableOptions, text.data);},
                    error: function (jqXHR, textStatus, errorThrown) {alert(jqXHR.responseText);}
                });
            } else {tableObject = grouptable.init(tableOptions, tableOptions.data);}
            return tableObject;
        },

        // 渲染表格
        init: function (param, data) {
            console.log("init start:"+(new Date()-window.istime));
            var doneCallback = param.done;
            var groups = {};
            var groupCols = param.groupCols;

            // 补上id和pid字段，同时构建分组数据
            for (var i = 0; i < data.length; i++) {
                var paths = new Array(groupCols.length);
                for(var depth=0; depth<paths.length; depth++){
                    var curValue = data[i][groupCols[depth].field]!==undefined?data[i][groupCols[depth].field]:"（空）";
                    var curText = (typeof groupCols[depth].valueFormat === 'function')?groupCols[depth].valueFormat(curValue):curValue;
                    paths[depth] = depth==0?curValue:(paths[depth-1]+"+"+curValue);
                    var groupKey =  paths[depth];
                    var groupPKey = (depth==0?param.treeSpid:paths[depth-1]);
                    var groupCount = groups.hasOwnProperty(groupKey)?(groups[groupKey].$treedatanums+1):1;
                    var groupTitle = groupCols[depth].tpl
                        .replaceAll("#name#",groupCols[depth].name)
                        .replaceAll("#value#",curText)
                        .replaceAll("#count#",groupCount);
                    var groupInfo = {$treeid: groupKey, $treevalue: curValue, $treegroupname: groupCols[depth].name, $treetext: curText, $treepid: groupPKey, $treetitle: groupTitle, $treetype: "g", $treedatanums:groupCount, $treedepth:depth};
                    groups[groupKey] = groupInfo;
                }

                var tt = data[i];
                $.extend(true,tt,{$treeid:paths[paths.length-1]+"+"+(("00000"+i).substr(-5)), $treepid:paths[paths.length-1], $treetype:"d", $treedepth:groupCols.length});
            }
            //将分组数据附加到表数据中
            data.unshift(...Object.values(groups));
            console.log("分组数量："+Object.keys(groups).length);
            //console.log(data);

            // 对数据进行排序
            var mData = new Array(data.length);
            var xindex = 0;
            var index4all = 0;
            var buildGroup = function (s_pid, dataArr) {
                var index4group = 0;
                for (var i = 0; i < dataArr.length; i++) {
                    if (dataArr[i] && dataArr[i].$treepid == s_pid) {
                        if(dataArr[i].$treetype=="d") {
                            dataArr[i].$index4all = ++index4all;
                            dataArr[i].$index4group = ++index4group;
                            dataArr[i].isParent = false;
                        }else{
                            dataArr[i].isParent = true;
                        }
                        mData[xindex++] = dataArr[i];
                        var thisid = dataArr[i].$treeid;
                        dataArr[i] = null;
                        buildGroup(thisid, dataArr);
                    }

                }
            };
            buildGroup(param.treeSpid, data);
            //console.log(mData);

            // 重写参数
            param.url = undefined;
            param.data = mData;
            param.limit = mData.length;
            param.$initConfig.data = mData;
            param.$initConfig.$_groups = groups;

            //TODO 修改序号列定义，改为只为数据行标注序号
            for(var i=0; i<param.cols[0].length; i++){
                if(param.cols[0][i].type == "numbers") {
                    param.cols[0][i].type = "xnumbers";
                    param.cols[0][i].templet = function (d) {return d.$treetype == "g"?"":d.$index4all;}
                }
                //隐藏列不允许固定
                if(param.cols[0][i].hide) delete param.cols[0][i].fixed;
            }

            //TODO 强制所有列进行重新排序 fixedLeft [fixedLeft+hide] normal hide fixedRight fixedRight+hide
            var getColSortv = function(a){
                var result = 50;
                if(a.fixed == "left") result-=10;
                if(a.fixed == "right") result+=10;
                if(a.hide) result += 5;
                return result;
            }
            param.cols[0].sort(function(a,b){return getColSortv(a)-getColSortv(b);});
            //第一列不允许隐藏
            if((param.cols[0][0].type || "normal")==="normal") param.cols[0][0].type="nothide";

            var emptyHtml = '<span class="groupTable-empty"></span>';
            var groupIconHtml = '<i class="layui-icon layui-icon-triangle-d"></i>';//'<i class="layui-icon layui-icon-triangle-d"></i> <i class="layui-icon layui-icon-layer"></i>';
            var dataIconHtml = '';//'<i class="layui-icon layui-icon-file"></i>';

            var templetCallBack = param.cols[0][param.groupColIndex].templet;
            param.cols[0][param.groupColIndex].templet = function (d) {
                var hasIndent = d.$treetype == "g" || (param.dataIndent && param.cols[0][param.groupColIndex].type!="xnumbers");
                var iconHtml = emptyHtml.repeat(hasIndent?d.$treedepth:0) + (d.$treetype == "g"?groupIconHtml:dataIconHtml);
                var originalText = d[param.cols[0][param.groupColIndex].field];
                if(templetCallBack){//参考table中parseTempData方法处理表格原数据
                    originalText = (typeof templetCallBack === 'function')?templetCallBack(d):(layui.laytpl($(templetCallBack).html() || String(templetCallBack)).render(d) );
                }
                var divText = d.$treetype == "g"?d.$treetitle:originalText;
                var divHtml = '<span class="groupTable-icon open" ' +
                    'les-index="' + d.LAY_TABLE_INDEX + '" ' +
                    'lay-tid="' + d.$treeid + '" ' +
                    'lay-tpid="' + d.$treepid + '" ' +
                    'lay-gtype="' + d.$treetype + '">' + iconHtml +
                    '</span>' +
                    '<span class="groupTable-title">' + divText + '</span>';
                return divHtml;
            };

            param.done = function (res, curr, count) {
                console.log("done start:"+(new Date()-window.istime));
                //console.log(param.$initConfig);
                $(param.elem).next().addClass('groupTable');
                $(param.elem).next().attr('groupLinkage', param.groupLinkage);
                $(param.elem).next().attr('lazyLoad', param.lazyLoad);
                $(param.elem).next().attr('lineWrap', param.lineWrap);

                //TODO 分组行合并单元格
                /**/
                var tableobj = $(param.elem).next().children('div.layui-table-box');
                var mobj = tableobj.children('div.layui-table-main').children('table:first');
                var lobj = tableobj.children('div.layui-table-fixed-l').children('div.layui-table-body').children('table:first');
                var robj = tableobj.children('div.layui-table-fixed-r').children('div.layui-table-body').children('table:first');
                var colspanMain = mobj.children('tbody').children('tr:first').children().length - param.groupColIndex;
                var mergeWidthMain = mobj.width()-31;
                var colspanFixedLeft = lobj.children('tbody').children('tr:first').children().length;
                var mergeWidthFixedLeft = lobj.width()-31;
                var colspanFixedRight = robj.children('tbody').children('tr:first').children().length;
                var mergeWidthFixedRight = robj.width()-31;

                //tableobj.children('div.layui-table-main').children('table').children('tbody').children('tr').children('td').children('div').children('span[lay-gtype="g"]').each(function (i, e) {
                //mobj.children('tbody').children('tr').children('td').children('div').children('span[lay-gtype="g"]').each(function (i, e) {
                mobj.find('span[lay-gtype="g"]').each(function (i, e) {
                    $(this).parent().parent().attr("colspan", colspanMain);
                    $(this).parent().parent().nextAll().remove();
                    $(this).parent().parent().removeClass("layui-hide");
                    $(this).parent().width(mergeWidthMain);
                    if(lobj.length>0 && !param.cols[0][0].hide) $(this).parent().children().hide();
                    var idx = $(this).parent().parent().parent().attr("data-index");
                    //tableobj.children('div.layui-table-fixed-r').children('div.layui-table-body').children('table').children('tbody').children('tr:eq('+idx+')').children('td:first').children('div').each(function (i, e) {
                    robj.children('tbody').children('tr:eq('+idx+')').children('td:first').children('div').each(function (i, e) {
                        $(this).parent().attr("colspan", colspanFixedRight);
                        $(this).parent().nextAll().remove();
                        $(this).width(mergeWidthFixedRight);
                        $(this).html("");
                    });
                });
                //tableobj.children('div.layui-table-fixed-l').children('div.layui-table-body').children('table').children('tbody').children('tr').children('td').children('div').children('span[lay-gtype="g"]').each(function (i, e) {
                //lobj.children('tbody').children('tr').children('td').children('div').children('span[lay-gtype="g"]').each(function (i, e) {
                lobj.find('span[lay-gtype="g"]').each(function (i, e) {
                    $(this).parent().parent().attr("colspan", colspanFixedLeft);
                    $(this).parent().parent().nextAll().remove();
                    $(this).parent().width(mergeWidthFixedLeft);
                });

                if (param.defaultClose) {
                    grouptable.foldAll(param.elem);
                }
                console.log("customer done start:"+(new Date()-window.istime));
                if (doneCallback) {
                    doneCallback(res, curr, count);
                }
                console.log("customer done end:"+(new Date()-window.istime));

                if(param.lineWrap) resizeRowHeight(tableobj);
                console.log("set divHeight end:"+(new Date()-window.istime));

            };
            // 渲染表格
            //console.log(param);
            console.log("table render start:"+(new Date()-window.istime));
            //console.log(param.data);
            var tobj = table.render(param);
            tobj.config = param.$initConfig;
            tobj.reload = function(extraConfig){grouptable.render(Object.assign(param.$initConfig,extraConfig));}
            tobj.expandAll = function(){grouptable.expandAll(param.elem);};
            tobj.foldAll = function(){grouptable.foldAll(param.elem);};
            console.log("table render done:"+(new Date()-window.istime));
            //TODO 固定列同步滚动
            var initObj = $(param.elem).next().children("div.layui-table-box");
            initObj.children("div.layui-table-main").off("scroll").on("scroll",function(event){
                var othis = $(this)
                    ,scrollLeft = othis.scrollLeft()
                    ,scrollTop = othis.scrollTop();
                initObj.find("div.layui-table-header").scrollLeft(scrollLeft);
                initObj.find("div.layui-table-total").scrollLeft(scrollLeft);
                initObj.children("div.layui-table-fixed:not(div.layui-table-fixed-scroll)").children("div.layui-table-body").scrollTop(scrollTop);
            });
            initObj.children("div.layui-table-fixed").children("div.layui-table-body").on("mouseenter",function(event){
                $(this).parent().addClass("layui-table-fixed-scroll");
                $(this).on("scroll", function(){
                    var st = $(this).scrollTop();
                    initObj.children("div.layui-table-main").scrollTop(st);
                })
            }).on("mouseleave",function(){
                $(this).parent().removeClass("layui-table-fixed-scroll");
                $(this).off("scroll");
            });
            console.log("init done:"+(new Date()-window.istime));
            initObj.attr("click","false");
            initObj.on("mousedown", function(){
                initObj.attr("click","true");
            }).on("mouseup", function(){
                initObj.attr("click","false");
            }).on("mousemove", function(e) {//鼠标释放
                if(initObj.attr("click")==="true") resizeGroupDiv(initObj, param.lineWrap);
            });
            return tobj;
        },
        // 展开/折叠行
        toggleRows: function ($dom, linkage) {
            var type = $dom.attr('lay-gtype');
            // console.info($dom);
            if ('d' == type) {return;}
            var mId = $dom.attr('lay-tid');
            var isOpen = $dom.hasClass('open');

            if (isOpen) {$dom.removeClass('open');} else {$dom.addClass('open');}
            $dom.closest('tbody').find('tr').each(function () {
                var $ti = $(this).find('.groupTable-icon');
                var pid = $ti.attr('lay-tpid');
                var gtype = $ti.attr('lay-gtype');
                var tOpen = $ti.hasClass('open');
                var les_index = $ti.attr('les-index');
                if (mId == pid) {
                    if (isOpen) {
                        $(this).hide();
                        $(".layui-table-body tr[data-index='"+(les_index)+"']").hide();
                        $(".layui-table-fixed tr[data-index='"+(les_index)+"']").hide();
                        if ('g' == gtype && tOpen == isOpen) closeA($ti);
                    } else {
                        $(this).show();
                        $(".layui-table-body tr[data-index='"+(les_index)+"']").show();
                        $(".layui-table-fixed tr[data-index='"+(les_index)+"']").show();
                        if (linkage && 'g' == gtype && tOpen == isOpen) closeA($ti);
                    }
                }
            });
        },
        // 展开所有
        expandAll: function (dom) {
            $(dom).next('.groupTable').find('.layui-table-body tbody tr').each(function () {
                var $ti = $(this).find('.groupTable-icon');
                var gtype = $ti.attr('lay-gtype');
                var tOpen = $ti.hasClass('open');
                if ('g' == gtype && !tOpen) $ti.trigger('click');
            });
        },
        // 折叠所有
        foldAll: function (dom) {
            $(dom).next('.groupTable').find('.layui-table-body tbody tr').each(function () {
                var $ti = $(this).find('.groupTable-icon');
                var gtype = $ti.attr('lay-gtype');
                var tOpen = $ti.hasClass('open');
                if ('g' == gtype && tOpen) $ti.trigger('click');
            });
        }
    };

    // 给图标列绑定事件
    $('body').on('click', '.groupTable .groupTable-icon', function (event) {closeA($(this));});

    function resizeGroupDiv(tableobj,lineWrap){
        var mobj = tableobj.children('div.layui-table-header').children('table:first');
        var lobj = tableobj.children('div.layui-table-fixed-l').children('div.layui-table-header').children('table:first');
        var mergeWidthMain = mobj.width()-31;
        var mergeWidthFixedLeft = lobj.width()-31;
        tableobj.children('div.layui-table-main').children('table').children('tbody').children('tr').children('td').children('div').children('span[lay-gtype="g"]').each(function (i, e) {
            $(this).parent().width(mergeWidthMain);
        });
        tableobj.children('div.layui-table-fixed-l').children('div.layui-table-body').children('table').children('tbody').children('tr').children('td').children('div').children('span[lay-gtype="g"]').each(function (i, e) {
            $(this).parent().width(mergeWidthFixedLeft);
        });
        if(lineWrap) resizeRowHeight(tableobj);
    }

    function resizeRowHeight(tableobj){
        //var rowcount = tableobj.children('div.layui-table-main').children('table').children('tbody').children().length;
        var rowcount = tableobj.find('tr[data-index]:last').attr("data-index")+1;
        var heights = new Array(Number(rowcount)).fill(0);
        tableobj.find('tr[data-index]').css("height","auto");
        tableobj.find('tr[data-index]').each(function (){
            var trIdx = $(this).attr("data-index");
            var thisHeight = $(this).height();
            heights[trIdx] = thisHeight>heights[trIdx]?thisHeight:heights[trIdx];
        })
        tableobj.find('tr[data-index]').each(function (){
            var trIdx = $(this).attr("data-index");
            $(this).height(heights[trIdx]);
        })
    }

    function closeA(ele){
        var groupLinkage = ele.parents('.groupTable').attr('groupLinkage');
        grouptable.toggleRows(ele, "true" === groupLinkage);
    }

    exports('grouptable', grouptable);
});

